//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <core.h>
#include <_hal.h>
#include <_schedule.h>

//
// SoftRealTimeScheduleClass
//
void SoftRealTimeScheduleClass::Initialize()
{
}

void SoftRealTimeScheduleClass::InitializeThread(Thread *pThread)
{
    assert(pThread);
    assert(pThread->m_pScheduleClass == this);

    pThread->m_uBasePriority = SOFTREALTIME_DEFAULT_PRIORITY;
    pThread->m_uDynamicPriority = SOFTREALTIME_DEFAULT_PRIORITY;
    pThread->m_nTimeQuota = s_nBaseTimeQuotas[SOFTREALTIME_DEFAULT_PRIORITY];

    pThread->m_bInherit = FALSE;

    pThread->m_pEffectiveScheduleClass = pThread->m_pScheduleClass;
    pThread->m_uEffectiveSchedulePolicy = pThread->m_uSchedulePolicy;

    pThread->m_uEffectiveBasePriority = pThread->m_uBasePriority;
    pThread->m_uEffectiveDynamicPriority = pThread->m_uDynamicPriority;
    pThread->m_nEffectiveTimeQuota = pThread->m_nTimeQuota;
}

void SoftRealTimeScheduleClass::SetThreadPriority(
    Thread *pThread, ThreadPriority priority, bool_t bRunning)
{
    assert(pThread);
    assert(pThread->m_pScheduleClass == this);
    assert(ThreadPriority_Highest >= priority);

    register uint_t uPriority = priority >> 7;
    assert(SOFTREALTIME_MAX_PRIORITY >= uPriority);

    if (uPriority == pThread->m_uBasePriority) return;

    pThread->m_uBasePriority = uPriority;
    pThread->m_uDynamicPriority = uPriority;

    if (pThread->m_nTimeQuota > s_nBaseTimeQuotas[uPriority]) {
        pThread->m_nTimeQuota = s_nBaseTimeQuotas[uPriority];
    }

    if (pThread->m_bInherit) return;

    pThread->m_uEffectiveBasePriority = uPriority;
    pThread->m_nEffectiveTimeQuota = pThread->m_nTimeQuota;

    if (pThread->m_uEffectiveDynamicPriority != pThread->m_uDynamicPriority) {
        if (bRunning) {
            pThread->Detach();
            m_listHeads[pThread->m_uDynamicPriority].InsertLast(pThread);
            RecalcMaxActivePriority(pThread->m_uDynamicPriority);
        }

        pThread->m_uEffectiveDynamicPriority = pThread->m_uDynamicPriority;
    }
}

ThreadPriority SoftRealTimeScheduleClass::GetThreadPriority(Thread *pThread)
{
    assert(pThread);
    assert(pThread->m_pScheduleClass == this);

    return (0 == pThread->m_uBasePriority)?
            0 : (pThread->m_uBasePriority << 7) + 0x7f;
}

void SoftRealTimeScheduleClass::OnThreadSleep(Thread *pThread)
{
    assert(pThread);
    assert(pThread->m_pEffectiveScheduleClass == this);
}

void SoftRealTimeScheduleClass::OnThreadWakeUp(Thread *pThread)
{
    assert(pThread);
    assert(pThread->m_pEffectiveScheduleClass == this);

    pThread->m_nEffectiveTimeQuota =
        s_nBaseTimeQuotas[pThread->m_uEffectiveBasePriority];
    if (!pThread->m_bInherit) {
        pThread->m_nTimeQuota = pThread->m_nEffectiveTimeQuota;
    }
}

void SoftRealTimeScheduleClass::OnThreadYield(Thread *pThread)
{
    assert(pThread);
    assert(pThread->m_pEffectiveScheduleClass == this);

    pThread->Detach();

    pThread->m_nEffectiveTimeQuota =
        s_nBaseTimeQuotas[pThread->m_uEffectiveBasePriority];
    if (!pThread->m_bInherit) {
        pThread->m_nTimeQuota = pThread->m_nEffectiveTimeQuota;
    }

    m_listHeads[pThread->m_uEffectiveDynamicPriority].InsertLast(pThread);
}

void SoftRealTimeScheduleClass::OnThreadSwitchOut(Thread *pThread)
{
    assert(pThread);
    assert(pThread->m_pEffectiveScheduleClass == this);

    pThread->m_uReadyStartTick = m_uElapsedTicks;

    pThread->m_nEffectiveTimeQuota =
        s_nBaseTimeQuotas[pThread->m_uEffectiveBasePriority];
    if (!pThread->m_bInherit) {
        pThread->m_nTimeQuota = pThread->m_nEffectiveTimeQuota;
    }
}

void SoftRealTimeScheduleClass::EnterRunningList(
    Thread *pThread, RunningReason reason)
{
    assert(pThread);

    pThread->m_uReadyStartTick = m_uElapsedTicks;
    m_listHeads[pThread->m_uEffectiveDynamicPriority].InsertLast(pThread);
    RecalcMaxActivePriority(pThread->m_uEffectiveDynamicPriority);
}

void SoftRealTimeScheduleClass::LeaveRunningList(Thread *pThread)
{
    assert(pThread);
    assert(pThread->m_pEffectiveScheduleClass == this);

    pThread->Detach();
    RecalcMaxActivePriority(-1);
}

void SoftRealTimeScheduleClass::UpdateTime(uint_t uTicks)
{
    m_uElapsedTicks += uTicks;
}

bool_t SoftRealTimeScheduleClass::UpdateThreadTime(
    Thread *pThread, uint_t uTicks)
{
    assert(pThread);
    assert(pThread->m_pEffectiveScheduleClass == this);

    if (pThread->m_uEffectiveSchedulePolicy == SoftRealTime_FIFO) return FALSE;

    pThread->m_nEffectiveTimeQuota -= uTicks * SOFTREALTIME_QUOTAS_PER_TICK;
    if (pThread->m_nEffectiveTimeQuota < 0) {
        pThread->m_nEffectiveTimeQuota = 0;
    }

    if (!pThread->m_bInherit) {
        pThread->m_nTimeQuota = pThread->m_nEffectiveTimeQuota;
    }

    if (0 == pThread->m_nEffectiveTimeQuota) {
        pThread->Detach();

        pThread->m_nEffectiveTimeQuota =
            s_nBaseTimeQuotas[pThread->m_uEffectiveBasePriority];
        if (!pThread->m_bInherit) {
            pThread->m_nTimeQuota = pThread->m_nEffectiveTimeQuota;
        }

        m_listHeads[pThread->m_uEffectiveDynamicPriority].InsertLast(pThread);

        return TRUE;
    }

    return FALSE;
}

Thread *SoftRealTimeScheduleClass::SelectNextThread()
{
    if (-1 == m_nMaxActivePriority) {
        return NULL;
    }

    assert(SOFTREALTIME_MIN_PRIORITY <= m_nMaxActivePriority
            && m_nMaxActivePriority <= SOFTREALTIME_MAX_PRIORITY);
    assert(!m_listHeads[m_nMaxActivePriority].IsEmpty());

    Thread *pThread = (Thread *)m_listHeads[m_nMaxActivePriority].First();

    return pThread;
}

SoftRealTimeScheduleClass::SoftRealTimeScheduleClass()
{
    m_type = ScheduleClassType_SoftRealTime;

    m_uElapsedTicks = 0;

    for (uint_t i = 0; i < SOFTREALTIME_NUMBEROF_PRIORITIES; i++) {
        m_listHeads[i].Initialize();
    }

    m_nMaxActivePriority = -1;
}

void SoftRealTimeScheduleClass::RecalcMaxActivePriority(int nNewActivePriority)
{
    if (m_nMaxActivePriority < nNewActivePriority) {
        m_nMaxActivePriority = nNewActivePriority;
    }
    else if (m_nMaxActivePriority > nNewActivePriority) {
        for (int i = m_nMaxActivePriority; i > nNewActivePriority; i--) {
            if (!m_listHeads[i].IsEmpty()) {
                m_nMaxActivePriority = i;
                return;
            }
        }
        m_nMaxActivePriority = nNewActivePriority;
    }
}

//
// schedule tables
//
int SoftRealTimeScheduleClass::s_nBaseTimeQuotas[] = {
    1 * SOFTREALTIME_QUOTAS_PER_TICK,
    1 * SOFTREALTIME_QUOTAS_PER_TICK,
    1 * SOFTREALTIME_QUOTAS_PER_TICK,
    1 * SOFTREALTIME_QUOTAS_PER_TICK,
    1 * SOFTREALTIME_QUOTAS_PER_TICK,
    1 * SOFTREALTIME_QUOTAS_PER_TICK,
    1 * SOFTREALTIME_QUOTAS_PER_TICK,
    1 * SOFTREALTIME_QUOTAS_PER_TICK,
};

SoftRealTimeScheduleClass g_softRealTimeScheduleClass;
